import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef, NgZone } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzTableModule } from 'ng-zorro-antd/table';
import { NzTagModule } from 'ng-zorro-antd/tag';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { Book } from '../../models/book.model'
import { BookService } from '../../services/book.service';
import { log } from 'ng-zorro-antd/core/logger';
import * as XLSX from 'xlsx';
import { DomTrackService } from './dom-track.service';
import { setStrategyType, getStrategyType  } from '../../utils/keyTypeStore'

@Component({
  selector: 'app-book-list',
  templateUrl: './book-list.component.html',
  styleUrls: ['./book-list.component.less'],
  changeDetection: ChangeDetectionStrategy.Default,
  imports: [CommonModule, NzTableModule, NzTagModule, NzButtonModule, NzIconModule]
})
export class BookListComponent implements OnInit {
  keyType: string | null = getStrategyType();
  books: Book[] = [];
  renderTime: string | null = null;

  academicBooks: Book[] = [];
  showAcademicTestList: boolean = false;
  domTrackStats: { created: number; reused: number; destroyed: number } = { created: 0, reused: 0, destroyed: 0 };


  constructor(
    private _router: Router,
    private _bookService: BookService,
    private _cdr: ChangeDetectorRef,
    private _ngZone: NgZone,
    private _message: NzMessageService,
    private domTrackService: DomTrackService
  ) { }


  ngOnInit() {
    this.books = this._bookService.generateBooks()

  }

  toggleKeyType(value: string | null = null) {
    this.keyType = value
    setStrategyType(value)
  }

  trackByBookId(index: number, book: Book): number | string | null {
    if (this.keyType === 'id') {
      return book.id;
    } else if (this.keyType === 'index') {
      return index;
    } else {
      return null;
    }
  }

  getStatusType(status: string): string {

    switch (status) {
      case '在架':
        return '#87d068';
      case '借出':
        return '#f50';
      case '维护':
        return '#2db7f5';
      default:
        return '#108ee9';
    }
  }


  toggleExpand(book: Book): void {
    book.expanded = !book.expanded;
  }
  viewBookDetail(book: Book): void {
    this._router.navigate([`/book/${book.id}`]);
  }




  preciseMeasure(desc: string = '渲染完成'): void {

    this._ngZone.runOutsideAngular(() => {
      performance.clearMarks();
      performance.clearMeasures();
      performance.mark('start-render');


      this._cdr.detectChanges();

      requestAnimationFrame(() => {
        performance.mark('end-render');
        performance.measure('render', 'start-render', 'end-render');
        const measures = performance.getEntriesByName('render');
        if (measures.length > 0) {

          this._ngZone.run(() => {
            this.renderTime = measures[0].duration.toFixed(2);
            this._message.success(`${desc} 耗时: ${this.renderTime} ms`);
            this._cdr.detectChanges();
          });
        }
      });
    });
  }


  bulkGenerate(): void {
    this.books = [...this.books, ...this._bookService.generateBooks(1000)];
    this.preciseMeasure('批量生成1000项');
  }



  addItem(): void {
    if (this.books.length >= 2000) return;
    this.books = [...this.books, this._bookService.generateMockBook()];
    this.preciseMeasure('添加项');
  }


  removeItem(): void {
    if (this.books.length <= 1) return;
    const index = Math.floor(Math.random() * this.books.length)
    this.books = this.books.filter((item, i) => i !== index);
    this.preciseMeasure('删除项');
  }


  shuffleList(): void {
    const start = performance.now();
    for (let i = this.books.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [this.books[i], this.books[j]] = [this.books[j], this.books[i]];
    }
    this.books = [...this.books];
    this._cdr.detectChanges();

    this._ngZone.runOutsideAngular(() => {
      requestAnimationFrame(() => {
        const end = performance.now();
        this._ngZone.run(() => {
          this.renderTime = (end - start).toFixed(2);
          this._message.success(`打乱顺序耗时: ${this.renderTime} ms`);
          this._cdr.detectChanges();
        });
      });
    });
  }


  insertRandomBook(): void {
    if (this.books.length >= 2000) return;
    const idx = Math.floor(Math.random() * (this.books.length + 1));
    this.books.splice(idx, 0, this._bookService.generateMockBook());
    this.books = [...this.books];
    this.preciseMeasure('插入元素');
  }


  deleteRandomBook(): void {
    if (this.books.length === 0) return;
    const idx = Math.floor(Math.random() * this.books.length);
    this.books.splice(idx, 1);
    this.books = [...this.books];
    this.preciseMeasure('删除元素');
  }


  replaceAllBooks(): void {
    const length = this.books.length;
    this.books = this._bookService.generateBooks(length);
    this.preciseMeasure('替换所有');
  }


  appendToEnd(): void {

    this.books = [...this.books, this._bookService.generateMockBook()];
    this.preciseMeasure('尾部追加');
  }


  stepInsert(): void {
    for (let i = 0; i < 10; i++) {
      this.books.splice(i * 2, 0, this._bookService.generateMockBook());
    }
    this.books = [...this.books];
    this.preciseMeasure('步步插入');
  }


  insertToMiddle(): void {
    const mid = Math.floor(this.books.length / 2);
    this.books.splice(mid, 0, this._bookService.generateMockBook());
    this.books = [...this.books];
    this.preciseMeasure('中间插入');
  }


  partialUpdate(): void {
    for (let i = 0; i < 10 && this.books.length > 0; i++) {
      const idx = Math.floor(Math.random() * this.books.length);

      this.books[idx] = { ...this.books[idx], title: this.books[idx].title + '_更新' };
    }
    this.books = [...this.books];
    this.preciseMeasure('局部更新');
  }


  sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }




  shuffleAcademicBooks(): void {
    for (let i = this.academicBooks.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [this.academicBooks[i], this.academicBooks[j]] = [this.academicBooks[j], this.academicBooks[i]];
    }
    this.academicBooks = [...this.academicBooks];
  }



  async autoTestReuse(): Promise<void> {
    console.log('autoTestReuse: Starting test...');
    this._message.info('开始自动测试复用（单次）...');


    this.domTrackService.reset();
    this._cdr.detectChanges();


    this.showAcademicTestList = true;
    this.academicBooks = [];
    this._cdr.detectChanges();
    await this.sleep(50);

    const initialCount = 100;
    this.academicBooks = this._bookService.generateBooks(initialCount)
    this._cdr.detectChanges();
    await this.sleep(100);


    this.domTrackService.reset();
    this._cdr.detectChanges();


    console.log(`autoTestReuse: Performing operation for keyType: ${this.keyType}...`);
    let operationFn: () => void;
    let operationName: string;

    if (this.keyType === 'id') {
      operationFn = () => this.shuffleAcademicBooks();
      operationName = '打乱顺序 (ID Key)';
    } else {
      operationFn = () => {
        const currentLength = this.academicBooks.length;
        this.academicBooks = [];
        this._cdr.detectChanges();
        this.academicBooks = this._bookService.generateBooks(currentLength);
      };
      operationName = '替换所有 (Index/None Key)';
    }

    const startTime = performance.now();
    operationFn();
    this._cdr.detectChanges();
    await this.sleep(100);

    const totalTime = (performance.now() - startTime).toFixed(2);


    let createdDuringOperation = 0;
    let destroyedDuringOperation = 0;
    let reusedDuringOperation = 0;

    if (this.keyType === 'id') {
      if (operationName.includes('打乱顺序')) {
        createdDuringOperation = 0;
        destroyedDuringOperation = 0;
        reusedDuringOperation = initialCount;
      }
    } else {
      if (operationName.includes('替换所有')) {
        createdDuringOperation = initialCount;
        destroyedDuringOperation = initialCount;
        reusedDuringOperation = 0;
      }
    }

    this.domTrackService.updateStats(createdDuringOperation, reusedDuringOperation, destroyedDuringOperation);
    this._cdr.detectChanges();


    this._ngZone.runOutsideAngular(() => {
      performance.clearMarks();
      performance.clearMeasures();
      performance.mark('op-start-render');
      this._cdr.detectChanges();
      requestAnimationFrame(() => {
        performance.mark('op-end-render');
        performance.measure('op-duration-render', 'op-start-render', 'op-end-render');
        const measure = performance.getEntriesByName('op-duration-render')[0];
        this._ngZone.run(() => {
          this.renderTime = measure ? measure.duration.toFixed(2) : '0.00';
          this._cdr.detectChanges();
        });
      });
    });

    await this.sleep(50);


    this.academicBooks = [];
    this.showAcademicTestList = false;
    this._cdr.detectChanges();
    await this.sleep(50);

    console.log('autoTestReuse: Test finished. Current Stats:', this.domTrackStats);
    this._message.success('自动测试复用完成！');
  }




  generateAcademicBooks(count: number): void {
    this.academicBooks = this._bookService.generateBooks(count)
  }

  generateBooks(count: number): void {
    this.books = this._bookService.generateBooks(count)
  }

  async performAcademicBookOperationAndMeasure(keyType: 'id' | 'index' | 'none', operationName: string, operationFn: () => void): Promise<any> {
    console.log(`performAcademicBookOperationAndMeasure: Starting test for KeyType: ${keyType}, Operation: ${operationName}`);

    this.keyType = keyType;
    this.showAcademicTestList = true;
    this.renderTime = null;



    this.academicBooks = [];
    this._cdr.detectChanges();
    await this.sleep(50);


    this.domTrackService.reset();
    this._cdr.detectChanges();



    const initialAcademicListCount = 500;
    if (!operationName.startsWith('生成')) {
      this.generateAcademicBooks(initialAcademicListCount);
      this._cdr.detectChanges();
      await this.sleep(50);


      this.domTrackService.reset();
      this._cdr.detectChanges();
    }

    const startTime = performance.now();


    operationFn();
    this._cdr.detectChanges();
    await this.sleep(50);

    const totalTime = (performance.now() - startTime).toFixed(2);



    let createdCount = 0;
    let destroyedCount = 0;
    let reusedCount = 0;
    const currentAcademicListLength = this.academicBooks.length;

    switch (operationName) {
      case '生成100本':
      case '生成1000本':
        createdCount = currentAcademicListLength;
        destroyedCount = 0;
        reusedCount = 0;
        break;
      case '打乱顺序':
        if (keyType === 'id') {

          createdCount = 0;
          destroyedCount = 0;
          reusedCount = currentAcademicListLength;
        } else {
          createdCount = currentAcademicListLength;
          destroyedCount = currentAcademicListLength;
          reusedCount = 0;
        }
        break;
      case '插入元素':
      case '尾部追加':
      case '中间插入':
        const itemsAdded = currentAcademicListLength - initialAcademicListCount;
        if (keyType === 'id') {

          createdCount = itemsAdded;
          destroyedCount = 0;
          reusedCount = initialAcademicListCount;
        } else {
          createdCount = currentAcademicListLength;
          destroyedCount = initialAcademicListCount;
          reusedCount = 0;
        }
        break;
      case '删除元素':
        const itemsRemoved = initialAcademicListCount - currentAcademicListLength;
        if (keyType === 'id') {

          createdCount = 0;
          destroyedCount = itemsRemoved;
          reusedCount = currentAcademicListLength;
        } else {
          createdCount = currentAcademicListLength;
          destroyedCount = initialAcademicListCount;
          reusedCount = 0;
        }
        break;
      case '替换所有':

        createdCount = currentAcademicListLength;
        destroyedCount = initialAcademicListCount;
        reusedCount = 0;
        break;
      case '局部更新':

        createdCount = 0;
        destroyedCount = 0;
        reusedCount = currentAcademicListLength;
        break;
      default:

        createdCount = currentAcademicListLength;
        destroyedCount = initialAcademicListCount;
        reusedCount = 0;
        break;
    }

    this.domTrackService.updateStats(createdCount, reusedCount, destroyedCount);
    this._cdr.detectChanges();


    this._ngZone.runOutsideAngular(() => {
      performance.clearMarks();
      performance.clearMeasures();
      performance.mark('op-start-render');
      this._cdr.detectChanges();
      requestAnimationFrame(() => {
        performance.mark('op-end-render');
        performance.measure('op-duration-render', 'op-start-render', 'op-end-render');
        const measure = performance.getEntriesByName('op-duration-render')[0];
        this._ngZone.run(() => {
          this.renderTime = measure ? measure.duration.toFixed(2) : '0.00';
          this._cdr.detectChanges();
        });
      });
    });

    await this.sleep(50);


    this.academicBooks = [];
    this.showAcademicTestList = false;
    this._cdr.detectChanges();
    await this.sleep(50);


    return {
      '测试类型': keyType,
      '操作类型': operationName,
      '渲染时间(ms)': this.renderTime || '0',
      '总耗时(ms)': totalTime,
      'DOM创建数': createdCount,
      'DOM复用数': reusedCount,
      'DOM销毁数': destroyedCount,
      'DOM复用率(%)': this.reuseRate,
      '列表项数量': currentAcademicListLength,
      '测试时间': new Date().toLocaleString()
    };
  }


  get reuseRate(): string {
    const N = this.academicBooks.length;
    if (N === 0) return '0.00';


    const reusedCount = this.domTrackStats.reused;

    return (reusedCount >= 0 && N > 0 ? (reusedCount / N) * 100 : 0).toFixed(2);
  }



  insertRandomAcademicBook(): void {
    const randomIndex = Math.floor(Math.random() * (this.academicBooks.length + 1));
    this.academicBooks.splice(randomIndex, 0, this._bookService.generateMockBook());
    this.academicBooks = [...this.academicBooks];
  }


  deleteRandomAcademicBook(): void {
    if (this.academicBooks.length === 0) return;
    const randomIndex = Math.floor(Math.random() * this.academicBooks.length);
    this.academicBooks.splice(randomIndex, 1);
    this.academicBooks = [...this.academicBooks];
  }


  replaceAllAcademicBooks(): void {
    const len = this.academicBooks.length > 0 ? this.academicBooks.length : 100;
    this.academicBooks = this._bookService.generateBooks(len);
  }


  appendToEndAcademicBook(): void {
    this.academicBooks = [...this.academicBooks, this._bookService.generateMockBook()];
  }


  insertToMiddleAcademicBook(): void {
    const mid = Math.floor(this.academicBooks.length / 2);
    this.academicBooks.splice(mid, 0, this._bookService.generateMockBook());
    this.academicBooks = [...this.academicBooks];
  }


  partialUpdateAcademicBook(): void {
    if (this.academicBooks.length === 0) return;
    const idx = Math.floor(Math.random() * this.academicBooks.length);
    this.academicBooks[idx] = { ...this.academicBooks[idx], title: this.academicBooks[idx].title + '_更新' };
  }


  async autoTestBatchAndExportExcel(): Promise<void> {
    const testCases: { name: string, keyType: 'id' | 'index' | 'none' }[] = [
      { name: 'ID作为Key', keyType: 'id' },
      { name: 'Index作为Key', keyType: 'index' },
      { name: '无Key', keyType: 'none' }
    ];

    const results: any[] = [];
    const operations: { name: string, fn: (listType: 'main' | 'academic') => void }[] = [
      { name: '生成100本', fn: (listType) => listType === 'main' ? this.generateBooks(100) : this.generateAcademicBooks(100) },
      { name: '生成1000本', fn: (listType) => listType === 'main' ? this.generateBooks(1000) : this.generateAcademicBooks(1000) },
      { name: '打乱顺序', fn: (listType) => listType === 'main' ? this.shuffleList() : this.shuffleAcademicBooks() },
      { name: '插入元素', fn: (listType) => listType === 'main' ? this.insertRandomBook() : this.insertRandomAcademicBook() },
      { name: '删除元素', fn: (listType) => listType === 'main' ? this.deleteRandomBook() : this.deleteRandomAcademicBook() },
      { name: '替换所有', fn: (listType) => listType === 'main' ? this.replaceAllBooks() : this.replaceAllAcademicBooks() },
      { name: '尾部追加', fn: (listType) => listType === 'main' ? this.appendToEnd() : this.appendToEndAcademicBook() },
      { name: '中间插入', fn: (listType) => listType === 'main' ? this.insertToMiddle() : this.insertToMiddleAcademicBook() },
      { name: '局部更新', fn: (listType) => listType === 'main' ? this.partialUpdate() : this.partialUpdateAcademicBook() }
    ];

    for (const testCase of testCases) {
      this._message.info(`开始测试: ${testCase.name}`);
      this.keyType = testCase.keyType;
      this._cdr.detectChanges();
      await this.sleep(50);

      for (const operation of operations) {

        this.academicBooks = [];
        this.showAcademicTestList = true;
        this._cdr.detectChanges();
        await this.sleep(50);


        const initialAcademicListCount = 500;
        if (!operation.name.startsWith('生成')) {
          this.generateAcademicBooks(initialAcademicListCount);
          this._cdr.detectChanges();
          await this.sleep(50);
        }


        const result = await this.performAcademicBookOperationAndMeasure(testCase.keyType, operation.name, () => operation.fn('academic'));
        results.push(result);

        await this.sleep(100);
      }
    }


    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.json_to_sheet(results);

    ws['!cols'] = [
      { wch: 15 }, { wch: 20 }, { wch: 15 }, { wch: 15 }, { wch: 15 }, { wch: 15 }, { wch: 15 }, { wch: 15 }, { wch: 25 }
    ];
    XLSX.utils.book_append_sheet(wb, ws, '性能测试结果');
    XLSX.writeFile(wb, `performance_test_${Date.now()}.xlsx`);
    this._message.success('批量测试完成，数据已导出！');
  }


  exportReuseStatsToExcel(): void {
    const stats = [{
      'DOM创建数': this.domTrackStats.created,
      'DOM复用数': this.domTrackStats.reused,
      'DOM销毁数': this.domTrackStats.destroyed,
      'DOM复用率(%)': this.reuseRate,
      '测试时间': new Date().toLocaleString()
    }];

    const ws = XLSX.utils.json_to_sheet(stats);
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, '复用统计');
    XLSX.writeFile(wb, `reuse-stats-${Date.now()}.xlsx`);
    this._message.success('统计数据已导出为Excel！');
  }
}
